package ui {
	
	// Imports
	
	import d2api.*;
	import d2components.*;
	import d2data.*;
	import d2hooks.*;
	import d2network.*;
	import flash.geom.Rectangle;
	import flash.utils.*;
	
	// Imports personnels
	
	import data.*;
	
	// Classe
	
	public class DamageCalcGUI {
		
		// APIs
		
		public var sysApi    : SystemApi;
		public var uiApi     : UiApi;		
		public var fightApi  : FightApi;		
		public var dataApi   : DataApi;
		public var playerApi : PlayedCharacterApi;
		
		// Composants graphiques
		
		public var ctr_global : GraphicContainer;
		public var lbl_title  : Label;
		public var chk_info1  : ButtonContainer;
		public var chk_info2  : ButtonContainer;
		public var chk_info3  : ButtonContainer;
		public var chk_info4  : ButtonContainer;
		public var btn_hide   : ButtonContainer;
		public var btn_show   : ButtonContainer;
		
		// Variables
		
		private var _spellInProcess   : Object  = null;
		private var _targetInProcess  : Object  = null;
		private var _effectsInProcess : Effets  = null;
		private var _tooltipInProcess : String  = "";
		private var _activatedModule  : Boolean = true;
		private var _textMode         : Number  = 1+2+4+8;
		
		// Accesseurs
		
		protected function getSpellInProcess() : Object {
			return _spellInProcess;
		}
		
		protected function setSpellInProcess(spellInProcess : Object) : void {
			_spellInProcess = spellInProcess;
		}
		
		protected function getTargetInProcess() : Object {
			return _targetInProcess;
		}
		
		protected function setTargetInProcess(targetInProcess : Object) : void {
			_targetInProcess = targetInProcess;
		}
		
		protected function getEffectsInProcess() : Effets {
			return _effectsInProcess;
		}
		
		protected function setEffectsInProcess(effectsInProcess : Effets) : void {
			_effectsInProcess = effectsInProcess;
		}
		
		protected function getTooltipInProcess() : String {
			return _tooltipInProcess;
		}
		
		protected function setTooltipInProcess(tooltipInProcess : String) : void {
			_tooltipInProcess = tooltipInProcess;
		}
		
		protected function getActivatedModule() : Boolean {
			return _activatedModule;
		}
		
		protected function setActivatedModule(activatedModule : Boolean) : void {
			_activatedModule = activatedModule;
		}
		
		protected function getTextMode() : Number {
			return _textMode;
		}
		
		protected function setTextMode(textMode : Number) : void {
			_textMode = textMode;
		}
		
		// Méthodes publiques
		
		public function main(params : Object) : void {
			// Etat des boutons
//			chk_info1.selected = false;
//			chk_info2.selected = false;
//			chk_info3.selected = false;
//			chk_info4.selected = false;
			// Clics sur les boutons
			uiApi.addComponentHook(chk_info1, "onRelease");
			uiApi.addComponentHook(chk_info2, "onRelease");
			uiApi.addComponentHook(chk_info3, "onRelease");
			uiApi.addComponentHook(chk_info4, "onRelease");
			uiApi.addComponentHook(btn_hide,  "onRelease");
			uiApi.addComponentHook(btn_show,  "onRelease");
			// Evenements
			sysApi.addHook(GameFightEnd,      onGameFightEnd);
			sysApi.addHook(FighterInfoUpdate, onFighterInfoUpdate);
			sysApi.addHook(CastSpellMode,     onCastSpellMode);
			sysApi.addHook(CancelCastSpell,   onCancelCastSpell);
			sysApi.addHook(FightEvent,        onFightEvent);
		}
		
		// Evenements
		
		public function onRelease(component : Object) : void {
			if (!getActivatedModule() || fightApi.isSpectator()) {
				setActivatedModule(false);
			} else if (component == btn_hide) {
				ctr_global.visible = false;
				btn_show.visible = true;
			} else if (component == btn_show) {
				ctr_global.visible = true;
				btn_show.visible = false;
			} else if (component == chk_info1 || component == chk_info2 || component == chk_info3 || component == chk_info4) {
				updateTextMode();
			}
		}
		
		public function onGameFightEnd(params : Object) : void {
			uiApi.unloadUi(uiApi.me().name);
		}
		
		public function onFightEvent(eventType : String , arg2 : Object , arg3 : Object) : void {
			if (!getActivatedModule() || fightApi.isSpectator()) {
				setActivatedModule(false);
			} else {
				setTargetInProcess(new Object());
				updateTooltip();
			}
		}
		
		public function onCancelCastSpell(spell : Object) : void {
			if (!getActivatedModule() || fightApi.isSpectator()) {
				setActivatedModule(false);
			} else {
				setSpellInProcess(null);
				updateTooltip();
			}
		}
		
		public function onCastSpellMode(spell : Object) : void {
			if (!getActivatedModule() || fightApi.isSpectator()) {
				setActivatedModule(false);
			} else {
				setSpellInProcess(spell);
				setTargetInProcess(null);
				updateTooltip();
			}
		}
		
		public function onFighterInfoUpdate(infosFighter : Object) : void {
			if (!getActivatedModule() || fightApi.isSpectator()) {
				setActivatedModule(false);
			} else {
				setTargetInProcess(infosFighter);
				updateTooltip();
			}
		}
		
		// Méthodes privées
		
		private function updateTextMode() : void {
			setTextMode( 0
				+ ( chk_info1.selected ? Math.pow(2, 0) : 0 )
				+ ( chk_info2.selected ? Math.pow(2, 1) : 0 )
				+ ( chk_info3.selected ? Math.pow(2, 2) : 0 )
				+ ( chk_info4.selected ? Math.pow(2, 3) : 0 )
			);
		}
		
		private function updateTooltip() : void {
			var tooltip : String = "";
			if (getSpellInProcess() != null) {
				var effets : Effets;
				if (getSpellInProcess() is WeaponWrapper) {
					effets = calculateEffects(getSpellInProcess().effects, 0, getSpellInProcess().effects, getSpellInProcess().criticalHitBonus, getSpellInProcess().criticalHitProbability, true);
				} else {
					var spell : SpellLevel = dataApi.getSpellLevelBySpell(dataApi.getSpell(getSpellInProcess().id), playerApi.knowSpell(getSpellInProcess().id));
					effets = calculateEffects(spell.effects, 0, spell.criticalEffect, 0, spell.criticalHitProbability, false);
				}
				tooltip = effets.getText(getSpellInProcess().name, getTextMode());
			}
			if (getSpellInProcess() != null || getTargetInProcess() == null)
				displayTooltip(tooltip);
		}
		
		private function displayTooltip(effects : String) : void {
			if (effects != null && effects != "") {
				uiApi.showTooltip(uiApi.textTooltipInfo(effects), new Rectangle(uiApi.getMouseX() + 25, uiApi.getMouseY() + 25, 0, 0));
				uiApi.showTooltip(uiApi.textTooltipInfo(effects), new Rectangle(uiApi.getMouseX() + 25, uiApi.getMouseY() + 25, 0, 0));
			} else {
				uiApi.hideTooltip();
			}
		}
		
		private function calculateEffects(EffectListNoCC : * , criticalHitBonusNoCC : int, EffectListCC : * , criticalHitBonusCC : int, probability : int, weapon : Boolean) : Effets {
			// Personnages concernés
			var launcher : CharacterCharacteristicsInformations = playerApi.characteristics() as CharacterCharacteristicsInformations;
			var target : FighterInformations = null;
			if (getTargetInProcess() != null)
				target = fightApi.getFighterInformations(getTargetInProcess().contextualId);
			// Calcul des effets
			var resultat : Effets = new Effets();
			resultat.setClassiques(calculateEffect(launcher, target, EffectListNoCC, criticalHitBonusNoCC));
			resultat.setCritiques(calculateEffect(launcher,  target, EffectListCC,   criticalHitBonusCC));
			if (weapon)
				resultat.setTaux(launcher.criticalHitWeapon);
			else
				resultat.setTaux(calculateFullProbability(launcher, probability));
			if (getTargetInProcess() != null)
				resultat.setVitalite(fightApi.getFighterInformations(getTargetInProcess().contextualId).lifePoints);
			return resultat;
		}
		
		private function calculateEffect(launcher : CharacterCharacteristicsInformations, target : FighterInformations, list : *, bonus : int = 0) : Vector.<Effet> {
			var resultat : Vector.<Effet> = new Vector.<Effet>();
			for each (var item : Object in list) {
				if (item.category == 2 && item.effectId != 101)	{
					var info : Object = calculateEffectInfo(launcher, target, item.effectId);
					var effet : Effet = info.effect;
					var jetBaseMin : int;
					var jetBaseMax : int;
					if (item is EffectInstanceMinMax) {
						jetBaseMin = (item.min + bonus);
						jetBaseMax = (item.max + bonus);
						effet.setMin(calculateDamage(jetBaseMin, info.stats, info.dmg, info.resist, info.resFix));
						if (item.max == 0)
							effet.setMax(effet.getMin());
						else
							effet.setMax(calculateDamage(jetBaseMax, info.stats, info.dmg, info.resist, info.resFix));
					} else {
						jetBaseMin = item.diceNum;
						jetBaseMax = item.diceSide;
						effet.setMin(calculateDamage(jetBaseMin, info.stats, info.dmg, info.resist, info.resFix));
						if (item.diceSide == 0)
							effet.setMax(effet.getMin());
						else
							effet.setMax(calculateDamage(jetBaseMax, info.stats, info.dmg, info.resist, info.resFix));
						if (item.zoneSize > 0) {
							effet.setMin(1.1 * effet.getMin());
							effet.setMax(1.1 * effet.getMax());
						}
					}
					resultat.push(effet);
				}
			}
			return resultat;
		}
		
		private function calculateFullProbability(launcher : CharacterCharacteristicsInformations, base : int) : int {
			var resultat      : int    = base;
			var agilite       : int    = 0;
			var multiplicator : Number = 1;
			if (base > 1) {
				agilite = getCharacteristicTotal(launcher.agility);
				multiplicator = 1;
				if (agilite >= 8)
					multiplicator = Math.E * 1.1 / Math.log(12 + agilite);
				if (multiplicator > 1)
					multiplicator = 1;
				resultat = Math.floor((base - getCharacteristicTotal(launcher.criticalHit)) * multiplicator);
				if (resultat < 2)
					resultat = 2;
			}
			return resultat;
		}
		
		private function calculateEffectInfo(launcher : CharacterCharacteristicsInformations, target : FighterInformations, effectId : int) : Object {
			// Résultat
			var caracBonus : int = 0;
			var damagesElementalBonus : int = 0;
			var damagesBonus : int = getCharacteristicTotal(launcher.allDamagesBonus);
			var damagesBonusPercent : int = getCharacteristicTotal(launcher.damagesBonusPercent);
			var resistanceCible : int = 0;
			var resistanceCiblePercent : int = 0;
			var masteryModificator : Number = 1 + (getCharacteristicTotal(launcher.weaponDamagesBonusPercent)/100);
			// Effet
			var effet : Effet = new Effet();
			effet._id = effectId;
			if (effectId == 81) { // Gain de PDV pas d'élément
				effet.setKind(Type.SOIGNE);
				caracBonus = getCharacteristicTotal(launcher.intelligence);
				damagesBonusPercent = 0;
			} else if (effectId == 82) { // Vol de vie fixe
				effet.setKind(Type.VOLE_FIXE, Elem.FEU);
				caracBonus = 0;
				damagesBonusPercent = 0;
				if (target != null) {
					resistanceCiblePercent = target.fireResist;
					resistanceCible = target.fireFixedResist;
				}
			} else if (effectId == 91) { // Vol de vie (EAU)
				effet.setKind(Type.VOLE, Elem.EAU);
				caracBonus = getCharacteristicTotal(launcher.chance);
				damagesElementalBonus = getCharacteristicTotal(launcher.waterDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.waterResist;
					resistanceCible = target.waterFixedResist;
				}
			} else if (effectId == 92) { // Vol de vie (TERRE)
				effet.setKind(Type.VOLE, Elem.TERRE);
				caracBonus = getCharacteristicTotal(launcher.strength);
				damagesElementalBonus = getCharacteristicTotal(launcher.earthDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.earthResist;
					resistanceCible = target.earthFixedResist;
				}
			} else if (effectId == 93) { // Vol de vie (AIR)
				effet.setKind(Type.VOLE, Elem.AIR);
				caracBonus = getCharacteristicTotal(launcher.agility);
				damagesElementalBonus = getCharacteristicTotal(launcher.airDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.airResist;
					resistanceCible = target.airFixedResist;
				}
			} else if (effectId == 94) { // Vol de vie (FEU)
				effet.setKind(Type.VOLE, Elem.FEU);
				caracBonus = getCharacteristicTotal(launcher.intelligence);
				damagesElementalBonus = getCharacteristicTotal(launcher.fireDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.fireResist;
					resistanceCible = target.fireFixedResist;
				}
			} else if (effectId == 95) { // Vol de vie (NEUTRE)
				effet.setKind(Type.VOLE, Elem.NEUTRE);
				caracBonus = getCharacteristicTotal(launcher.strength);
				damagesElementalBonus = getCharacteristicTotal(launcher.neutralDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.neutralResist;
					resistanceCible = target.neutralFixedResist;
				}
			} else if (effectId == 96) { // Dommage (EAU)
				effet.setKind(Type.INFLIGE, Elem.EAU);
				caracBonus = getCharacteristicTotal(launcher.chance);
				damagesElementalBonus = getCharacteristicTotal(launcher.waterDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.waterResist;
					resistanceCible = target.waterFixedResist;
				}
			} else if (effectId == 97) { // Dommage (TERRE)
				effet.setKind(Type.INFLIGE, Elem.TERRE);
				caracBonus = getCharacteristicTotal(launcher.strength);
				damagesElementalBonus = getCharacteristicTotal(launcher.earthDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.earthResist;
					resistanceCible = target.earthFixedResist;
				}
			} else if (effectId == 98) { // Dommage (AIR)
				effet.setKind(Type.INFLIGE, Elem.AIR);
				caracBonus = getCharacteristicTotal(launcher.agility);
				damagesElementalBonus = getCharacteristicTotal(launcher.airDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.airResist;
					resistanceCible = target.airFixedResist;
				}
			} else if (effectId == 99) { // Dommage (FEU)
				effet.setKind(Type.INFLIGE, Elem.FEU);
				caracBonus = getCharacteristicTotal(launcher.intelligence);
				damagesElementalBonus = getCharacteristicTotal(launcher.fireDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.fireResist;
					resistanceCible = target.fireFixedResist;
				}
			} else if (effectId == 100) { // Dommage (NEUTRE)
				effet.setKind(Type.INFLIGE, Elem.NEUTRE);
				caracBonus = getCharacteristicTotal(launcher.strength);
				damagesElementalBonus = getCharacteristicTotal(launcher.neutralDamageBonus);
				if (target != null) {
					resistanceCiblePercent = target.neutralResist;
					resistanceCible = target.neutralFixedResist;
				}
			} else if (effectId == 108) { // Gain de PDV
				effet.setKind(Type.SOIGNE);
				caracBonus = getCharacteristicTotal(launcher.intelligence);
				damagesBonus = getCharacteristicTotal(launcher.healBonus);
				damagesBonusPercent = 0;
			} else if (effectId == 670) { // Perte de PDV (% de vie du caster) réduit
				effet.setKind(Type.SUBIT_POUR, Elem.NEUTRE);
				caracBonus = getCharacteristicTotal(launcher.vitality);
				damagesBonusPercent = 0;
				if (target != null) {
					resistanceCiblePercent = target.neutralResist;
					resistanceCible = target.neutralFixedResist;
				}
			} else if (effectId == 671) { // Perte de PDV (% de vie du caster) non réduit
				effet.setKind(Type.SUBIT_POUR, Elem.AUCUN);
				caracBonus = getCharacteristicTotal(launcher.vitality);
				damagesBonusPercent = 0;
			} else if (effectId == 672) { // Perte de PDV (% du milieu de vie du caster)
				effet.setKind(Type.SUBIT_POUR, Elem.NEUTRE);
				caracBonus = getCharacteristicTotal(launcher.vitality);
				damagesBonusPercent = 0;
				if (target != null) {
					resistanceCiblePercent = target.neutralResist;
					resistanceCible = target.neutralFixedResist;
				}
			} else if (effectId == 84) { // Vol de PA esquivable
				//caracBonus = (launcher.wisdom.alignGiftBonus + launcher.wisdom.base + launcher.wisdom.contextModif + launcher.wisdom.objectsAndMountBonus);
			} else if (effectId == 440) { // Vol de PA Non esquivable
				//caracBonus = (launcher.wisdom.alignGiftBonus + launcher.wisdom.base + launcher.wisdom.contextModif + launcher.wisdom.objectsAndMountBonus);
			} else if (effectId == 101) { // Perte de PA
				//caracBonus = (launcher.wisdom.alignGiftBonus + launcher.wisdom.base + launcher.wisdom.contextModif + launcher.wisdom.objectsAndMountBonus);
			}
			return {
				effect : effet,
				stats  : caracBonus + damagesBonusPercent,
				dmg    : damagesElementalBonus + damagesBonus,
				resist : resistanceCiblePercent,
				resFix : resistanceCible
			};
		}
		
		private function calculateDamage(base : int, carac : int, damage : int, resistance : int, resFixe : int) : int {
			var value : int = Math.floor(Number(1 - (resistance / 100)) * (base + damage + base * carac / 100) - resFixe);
			return (value < 0 ? 0 : value);
		}
		
		private function getCharacteristicTotal(carac : CharacterBaseCharacteristic) : int {
			return (carac.alignGiftBonus + carac.base + carac.contextModif + carac.objectsAndMountBonus);
		}
		
	}
	
}